回溯法—八皇后问题(N皇后)

八皇后问题

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

解题思路:
这里写图片描述
1.在8*8的棋盘上进行逐行试探,每一行进行逐格试探,判断该格是否能放一个皇后,即判断在该格对应的列,左斜线,右斜线上是否有皇后,若有则放,若无,则试探该行的下一个格子。
2.当该行已经放了皇后之后,跳到下一行;
若该行无法放入皇后,则说明之前放皇后的一行,皇后放的有问题,需要重新放,回退到该行放皇后的格子处,对后面的格子进行重新试探;依次类推,直到8行放完后,输出;

#include<iostream>
using namespace std;
int leftt[15]={0};//leftt控制左斜线 
int rightt[15]={0};//rightt控制右斜线 
int col[8]={0};//判断该列是否有皇后 
int Q[8]={0};//下标代表皇后,值代表列号 
int cnt=1;//计算当前为第几组解 
void print(){
    cout<<"第"<<cnt++<<"组解"<<endl;
    for(int i=0;i<8;i++){
        for(int j=0;j<8;j++){
            if(Q[i]==j) cout<<"Q ";
            else cout<<"X ";
        }
        cout<<endl;
    }

}
void Queen(int i){//传入行号 
    if(i==8){
        print();//当i为8时,说明棋盘已经被放满 
    }
    else{
        for(int j=0;j<8;j++){//依次遍历当前行的每一个格子 
            if(!col[j]&&!leftt[i+j]&&!rightt[7+i-j]){//若该格子可以放皇后,则将值改1 
                col[j]=leftt[i+j]=rightt[7+i-j]=1;
                Q[i]=j;//将皇后的位置存入 
                Queen(i+1);//再给下一行放 
                col[j]=leftt[i+j]=rightt[7+i-j]=0;//从上一行退出来后,这说明这一行的皇后的位置不对,故抹去皇后的位置 
            }
        }
    }
}
int main(void){
    Queen(0);
    return 0;
}

就写这么多,如果那里不清楚联系我QQ294177133

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++经典 八皇后问题的C++源程序 #include <stdio.h> #define N 8 void main() { void move(int a[][N],int n); int Judge(int a[][N]); //a[N][N]表示棋盘,每个元素表示一个位置,为0表示没有放置皇后,为1表示放置皇后 //num记录摆放方法的数目 int a[N][N]={0},i,j,n=0,num=0; //初始条件,让每个皇后都处于每行的第一列 for(i=0;i<N;i++) a[i][0]=1; //判断是否所有的皇后都移到最后一列了 while(!n) { move(a,N-1); if(Judge(a)) { for(i=0;i<N;i++) { for(j=0;j<N;j++) if (a[i][j]) printf("%2d",j); /* for(j=0;j<N;j++) printf(" %d",a[i][j]); printf("\n"); */ } num++; printf("\t\t%d\n",num); } //只有所有的皇后都移到最后一列时,最后一列值均为1,他们的乘积为1;否则为0 for(i=0,n=1;i<N;i++) n*=a[i][N-1]; } } //是否符合规则 int Judge(int a[][N]) { int sum,x,y,i,j,k; for(i=0;i<N;i++) { for(j=0;j<N;j++) if(a[i][j]) { //求同一列的皇后数,用于判断是否有皇后处于同一列 for(k=0,sum=0;k<N;k++) if(a[k][j]) sum++; //判断是不是在同一列,同一列数目超过1了 if(sum>1) return(0); //同行就不用判断了,因为赋初值时,每行只有一个皇后 //判断是不是在同一对角线上 //左上 for(x=i-1,y=j-1;x>=0&&y>=0;x--,y--) if(a[x][y]) return(0); //右下 for(x=i+1,y=j+1;x<N&&y<N;x++,y++) if(a[x][y]) return(0); //左下 for(x=i-1,y=j+1;x>=0&&y<N;x--,y++) if(a[x][y]) return(0); //右上 for(x=i+1,y=j-1;x<N&&y>=0;x++,y--) if(a[x][y]) return(0); } } return(1); } //将第n行的皇后向后移动一个位置 void move(int a[][N],int n) { int j; for(j=0;j<N;j++) if(a[n][j]) if(j<N-1) //不是最后一列时,向下一列移动 { a[n][j]=0; a[n][j+1]=1; return; } else //是最后一列时,向本行列首移动,并且移动上一行 { a[n][j]=0; a[n][0]=1; move(a,n-1); return; } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值